home *** CD-ROM | disk | FTP | other *** search
/ BMUG Revelations / BMUG Revelations.toast / Utilities / Network / Ping 1.1 / Source / main.c next >
Text File  |  1992-04-18  |  17KB  |  910 lines

  1. //    Main.c
  2. //    Ping 1.0
  3. //
  4. //    A neat hack © 1992 Jon Wätte (h+@nada.kth.se)
  5. //
  6. //    Freeware - permission granted to study & distribute free of charge,
  7. //    however, you may not sell this source or any derivate thereof, nor
  8. //    may you distribute modified source or a derivate thereof.
  9.  
  10. #include "Util.h"
  11.  
  12. #define STRING_SIZE 100
  13. #define DELAY 40
  14. #define STACK 5000
  15. #define NAME_SIZE 33
  16.  
  17. #define pingClass 'Ping'
  18.  
  19. #define pingPing 'Ping'
  20. #define pingMessage 'Mesg'
  21.  
  22. #define pingSenderName 'Name'
  23. #define pingSenderText 'Text'
  24. #define pingSenderSound 'Snd '
  25. #define pingSenderPict 'Pict'
  26. #define pingSenderMisc 'Misc'
  27. #define pingSenderTime 'Time'
  28.  
  29. short topPart = 220 ;
  30. short bottomPart = 19 ;
  31. short lineWidth = 232 ;
  32. short lineHeight = 0 ;
  33. short leftMarg = 4 ;
  34. short topMarg = 0 ;
  35.  
  36. EventRecord gEvent ;
  37. WindowPtr gWindow = NULL ;
  38. int numLines = 0 ;
  39. unsigned char * * theLines = NULL ;
  40. FontInfo txInfo ;
  41. Boolean gRunning = 1 ;
  42. Rect textRect ;
  43. TEHandle teH = NULL ;
  44. LocationNameRec theLocation ;
  45. Boolean hasDest = 0 ;
  46. PortInfoRec thePPCPort ;
  47. Str32 theNBPType ;
  48. Boolean isIn = 1 ;
  49. RgnHandle aRgn = NULL ;
  50. NMRec gNmRec ;
  51. unsigned char userName [ NAME_SIZE ] ;
  52.  
  53.  
  54. //    Standard toolbox initialization
  55. //
  56. static void
  57. InitMac ( void )
  58. {
  59.     InitGraf ( & qd . thePort ) ;
  60.     InitFonts ( ) ;
  61.     InitWindows ( ) ;
  62.     InitMenus ( ) ;
  63.     TEInit ( ) ;
  64.     InitDialogs ( NULL ) ;
  65.  
  66.     // Initializing the PPC toolbox is not strictly necessary, but nice...
  67.     PPCInit ( ) ;
  68.  
  69.     //    We only need a few Ks of stack since we don't use recursion or stack-based calls
  70.     SetApplLimit ( CurStackBase - STACK ) ;
  71.     //    Make sure we have our heap
  72.     MaxApplZone ( ) ;
  73.     //    And maybe we need another master pointer block
  74.     MoreMasters ( ) ;
  75. }
  76.  
  77.  
  78. //    Install a notification with sound, icon and diamond
  79. //
  80. static void
  81. Notification ( void )
  82. {
  83.     //    Only while we're in the background...
  84.     if ( ! isIn ) {
  85.  
  86.         //    Is it already allocated ?
  87.         if ( ! gNmRec . nmIcon ) {
  88.  
  89.             Clear ( gNmRec ) ;
  90.             gNmRec . qType = nmType ;
  91.             gNmRec . nmMark = 1 ;
  92.             gNmRec . nmIcon = GetResource ( 'SICN' , 128 ) ;
  93.             gNmRec . nmSound = ( Handle ) -1 ;
  94.             gNmRec . nmStr = NULL ;
  95.             gNmRec . nmResp = NULL ;
  96.             gNmRec . nmRefCon = 0L ;
  97.  
  98.             NMInstall ( & gNmRec ) ;
  99.         }
  100.     }
  101. }
  102.  
  103.  
  104. //    Add a string to the window. We use a cyclic buffer of pointers.
  105. //
  106. static void
  107. AddString ( unsigned char * str , short len , unsigned char * user )
  108. {
  109.     short ix ;
  110.     unsigned char * msg ;
  111.     Rect rect ;
  112.  
  113.     //    Check that we do not overwrite our buffers
  114.     if ( len > STRING_SIZE - 1 ) {
  115.  
  116.         len = STRING_SIZE - 1 ;
  117.     }
  118.     SetRect ( & rect ,  0 , 0 , lineWidth + leftMarg * 2 , topPart ) ;
  119.     SetEmptyRgn ( aRgn ) ;
  120.     ScrollRect ( & rect , 0 , - lineHeight , aRgn ) ;
  121.     EraseRgn ( aRgn ) ;
  122.     if ( len ) {
  123.  
  124.         BlockMove ( str , & theLines [ 0 ] [ 1 ] , len ) ;
  125.     }
  126.     theLines [ 0 ] [ 0 ] = len ;
  127.     msg = theLines [ 0 ] ;
  128.     if ( user [ 0 ] && len < STRING_SIZE - 4 - user [ 0 ] ) {
  129.  
  130.         AddPBuf ( msg , "\P (" ) ;
  131.         AddPBuf ( msg , user ) ;
  132.         AddPBuf ( msg , "\P)" ) ;
  133.     }
  134.     MoveTo ( leftMarg , ( numLines - 1 ) * lineHeight + topMarg ) ;
  135.     DrawString ( msg ) ;
  136.     for ( ix = 0 ; ix < numLines - 1 ; ix ++ ) {
  137.  
  138.         theLines [ ix ] = theLines [ ix + 1 ] ;
  139.     }
  140.     theLines [ numLines - 1 ] = msg ;
  141.     //    Notify the user that we received a message
  142.     Notification ( ) ;
  143. }
  144.  
  145.  
  146. //    Handle the Ping message AppleEvent
  147. //
  148. pascal static OSErr
  149. AEReceiveMessage ( AppleEvent * theEvent , AppleEvent * reply , long refCon )
  150. {
  151.     unsigned char s [ STRING_SIZE ] ;
  152.     unsigned char nm [ NAME_SIZE ] ;
  153.     short err ;
  154.     long type , size , nmSize ;
  155.  
  156.     //    Check for the text
  157.     err = AEGetParamPtr ( theEvent , pingSenderText , typeChar , ( void * ) & type ,
  158.         ( void * ) & s [ 1 ] , STRING_SIZE , & size ) ;
  159.  
  160.     //    And the name...
  161.     if ( ! err ) {
  162.  
  163.         err = AEGetParamPtr ( theEvent , pingSenderName , typeChar , ( void * ) & type ,
  164.             ( void * ) & nm [ 1 ] , STRING_SIZE , & nmSize ) ;
  165.         nm [ 0 ] = nmSize ;
  166.         if ( err ) {    //    X Brand - No Name
  167.  
  168.             nm [ 0 ] = 0 ;
  169.             err = 0 ;
  170.         }
  171.     }
  172.     if ( ! err ) {
  173.  
  174.         s [ 0 ] = '-' ;
  175.         AddString ( s , size + 1 , nm ) ;
  176.     }
  177.     if ( err ) {
  178.  
  179.         //    Must interacto to report error
  180.         if ( AEInteractWithUser ( 3600 , NULL , NULL ) ) {
  181.  
  182.             DSErrCode = err ;
  183.             ExitToShell ( ) ;
  184.         }
  185.         Fatal ( err ) ;
  186.     }
  187. }
  188.  
  189.  
  190. //    Open Application - initialize
  191. //
  192. pascal static OSErr
  193. AEOpenAppHandler ( AppleEvent * theEvent , AppleEvent * reply , long refCon )
  194. {
  195.     return noErr ;
  196. }
  197.  
  198.  
  199. //    Quit the application
  200. //
  201. pascal static OSErr
  202. AEQuitAppHandler ( AppleEvent * theEvent , AppleEvent * reply , long refCon )
  203. {
  204.     gRunning = 0 ;
  205.     return noErr ;
  206. }
  207.  
  208.  
  209. //    We have no documents
  210. //
  211. pascal static OSErr
  212. AEOpenDocHandler ( AppleEvent * theEvent , AppleEvent * reply , long refCon )
  213. {
  214.     return errAEEventNotHandled ;
  215. }
  216.  
  217.  
  218. //    We have no documents
  219. //
  220. pascal static OSErr
  221. AEPrintDocHandler ( AppleEvent * theEvent , AppleEvent * reply , long refCon )
  222. {
  223.     return errAEEventNotHandled ;
  224. }
  225.  
  226.  
  227. //    Initialize the application data
  228. //
  229. static void
  230. InitApp ( void )
  231. {
  232.     MenuHandle mh ;
  233.     Handle mBar ;
  234.     short ix ;
  235.  
  236.     //    Window
  237.     gWindow = GetNewWindow ( 128 , NULL , NULL ) ;
  238.     if ( ! gWindow ) {
  239.  
  240.         Fatal ( QDError ( ) ) ;
  241.     }
  242.     SelectWindow ( gWindow ) ;
  243.     ShowWindow ( gWindow ) ;
  244.  
  245.     SetPort ( gWindow ) ;
  246.     TextFont ( 1 ) ;
  247.     TextSize ( 10 ) ;
  248.     TextFace ( 0 ) ;
  249.     TextMode ( srcOr ) ;
  250.     //    Set up font data
  251.     GetFontInfo ( & txInfo ) ;
  252.     lineHeight = txInfo . ascent + txInfo . descent + txInfo . leading ;
  253.     numLines = topPart / lineHeight ;
  254.     topMarg = ( topPart - lineHeight * numLines ) / 2 + txInfo . ascent ;
  255.  
  256.     //    Allocate buffers for storing incoming message data
  257.     theLines = ( unsigned char * * ) NewPtrClear ( sizeof ( unsigned char * ) * numLines ) ;
  258.     if ( ! theLines ) {
  259.  
  260.         Fatal ( MemError ( ) ) ;
  261.     }
  262.     for ( ix = 0 ; ix < numLines ; ix ++ ) {
  263.  
  264.         theLines [ ix ] = ( unsigned char * ) NewPtrClear ( STRING_SIZE ) ;
  265.         if ( ! theLines [ ix ] ) {
  266.     
  267.             Fatal ( MemError ( ) ) ;
  268.         }
  269.     }
  270.  
  271.     //    Where do we input our text ?
  272.     textRect . top = 0 ;
  273.     textRect . bottom = ( bottomPart / lineHeight ) * lineHeight ;
  274.     textRect . left = 0 ;
  275.     textRect . right = lineWidth ;
  276.     OffsetRect ( & textRect , leftMarg , ( bottomPart - textRect . bottom ) / 2 + topPart + 1 ) ;
  277.  
  278.     //    Make input text edit
  279.     teH = TENew ( & textRect , & textRect ) ;
  280.     if ( ! teH ) {
  281.  
  282.         Fatal ( MemError ( ) ) ;
  283.     }
  284.  
  285.     //    Install menus
  286.     mBar = GetNewMBar ( 128 ) ;
  287.     if ( ! mBar ) {
  288.  
  289.         Fatal ( ResError ( ) ) ;
  290.     }
  291.     SetMenuBar ( mBar ) ;
  292.     DrawMenuBar ( ) ;
  293.     mh = GetMHandle ( 128 ) ;
  294.     if ( ! mh ) {
  295.  
  296.         Fatal ( ResError ( ) ) ;
  297.     }
  298.     AddResMenu ( mh , 'DRVR' ) ;
  299.  
  300.     //    Install AppleEvent handlers
  301.     AEInstallEventHandler ( pingClass , pingMessage , AEReceiveMessage , 0L , FALSE ) ;
  302.     AEInstallEventHandler ( kCoreEventClass , kAEOpenApplication , AEOpenAppHandler , 0L , FALSE ) ;
  303.     AEInstallEventHandler ( kCoreEventClass , kAEQuitApplication , AEQuitAppHandler , 0L , FALSE ) ;
  304.     AEInstallEventHandler ( kCoreEventClass , kAEOpenDocuments , AEOpenDocHandler , 0L , FALSE ) ;
  305.     AEInstallEventHandler ( kCoreEventClass , kAEPrintDocuments , AEPrintDocHandler , 0L , FALSE ) ;
  306.  
  307.     //    A few utility things
  308.     aRgn = NewRgn ( ) ;
  309.     if ( ! aRgn ) {
  310.  
  311.         Fatal ( MemError ( ) ) ;
  312.     }
  313.     Clear ( gNmRec ) ;
  314.     TEFeatureFlag ( teFOutlineHilite , TEBitSet , teH ) ;
  315.     GetUserName ( userName ) ;
  316. }
  317.  
  318.  
  319. //    Draw the contents of our (only) window
  320. //
  321. static void
  322. DrawWindow ( void )
  323. {
  324.     short ix ;
  325.  
  326.     PenNormal ( ) ;
  327.     PenPat ( qd . gray ) ;
  328.     MoveTo ( leftMarg , topPart ) ;
  329.     Line ( lineWidth , 0 ) ;
  330.     PenPat ( qd . black ) ;
  331.  
  332.     EraseRect ( & textRect ) ;
  333.     TEUpdate ( & textRect , teH ) ;
  334.  
  335.     //    Loop through our stored strings and draw
  336.     for ( ix = 0 ; ix < numLines ; ix ++ ) {
  337.  
  338.         MoveTo ( leftMarg , topMarg + ix * lineHeight ) ;
  339.         DrawString ( theLines [ ix ] ) ;
  340.     }
  341. }
  342.  
  343.  
  344. //    Handle the Update Event in gEvent
  345. //
  346. static void
  347. Update ( void )
  348. {
  349.     WindowPtr wp = ( WindowPtr ) gEvent . message ;
  350.  
  351.     SetPort ( wp ) ;
  352.     BeginUpdate ( wp ) ;
  353.     //    Only draw contents if it's our window
  354.     if ( wp == gWindow ) {
  355.  
  356.         DrawWindow ( ) ;
  357.     }
  358.     EndUpdate ( wp ) ;
  359. }
  360.  
  361.  
  362. //    Handle Activate Event in gEvent
  363. //
  364. static void
  365. Activate ( void )
  366. {
  367.     if ( ( WindowPtr ) gEvent . message == gWindow ) {
  368.  
  369.         if ( gEvent . modifiers & activeFlag ) {
  370.  
  371.             TEActivate ( teH ) ;
  372.  
  373.         } else {
  374.  
  375.             TEDeactivate ( teH ) ;
  376.         }
  377.     }
  378. }
  379.  
  380.  
  381. //    Handle mouseDown in our window
  382. //
  383. static void
  384. ClickWindow ( void )
  385. {
  386.     Point p = gEvent . where ;
  387.  
  388.     SetPort ( gWindow ) ;
  389.     GlobalToLocal ( & p ) ;
  390.     if ( PtInRect ( p , & textRect ) ) {
  391.  
  392.         TEClick ( p , gEvent . modifiers & shiftKey , teH ) ;
  393.     }
  394. }
  395.  
  396.  
  397. //    Our about box - nothing too fancy
  398. //    The Delays are not too "nice" but hey, it's an about box
  399. //
  400. static void
  401. DoAbout ( void )
  402. {
  403.     register short ix ;
  404.     register short wid ;
  405.     register short end ;
  406.     Str255 s ;
  407.     long l ;
  408.     Handle h ;
  409.  
  410.     //    Fill the window, slowly
  411.     SetPort ( gWindow ) ;
  412.     wid = gWindow -> portRect . right ;
  413.     end = gWindow -> portRect . bottom ;
  414.     for ( ix = 0 ; ix < end ; ix ++ ) {
  415.  
  416.         MoveTo ( 0 , ix ) ;
  417.         Line ( wid , 0 ) ;
  418.         Delay ( 1 , & l ) ;
  419.     }
  420.  
  421.     TextMode ( srcXor ) ;
  422.  
  423.     //    Draw version info
  424.     h = GetResource ( 'vers' , 1 ) ;
  425.     if ( h ) {
  426.  
  427.         BlockMove ( & ( * h ) [ 6 ] , s , ( * h ) [ 6 ] + 1 ) ; // Short Version
  428.         MoveTo ( gWindow -> portRect . right - StringWidth ( s ) - 5 ,
  429.             gWindow -> portRect . bottom - 5 ) ;
  430.         DrawString ( s ) ;
  431.         ReleaseResource ( h ) ;
  432.     }
  433.  
  434.     //    Draw our strings
  435.     Delay ( DELAY , & l ) ;
  436.     GetIndString ( s , 128 , 4 ) ;
  437.     ix = StringWidth ( s ) ;
  438.     MoveTo ( ( wid - ix ) / 2 , 30 ) ;
  439.     DrawString ( s ) ;
  440.  
  441.     Delay ( DELAY , & l ) ;
  442.     GetIndString ( s , 128 , 5 ) ;
  443.     ix = StringWidth ( s ) ;
  444.     MoveTo ( ( wid - ix ) / 2 , 50 ) ;
  445.     DrawString ( s ) ;
  446.  
  447.     //    Wait for click
  448.     Delay ( DELAY , & l ) ;
  449.     while ( ! Button ( ) ) {
  450.  
  451.         EventAvail ( 0 , & gEvent ) ;
  452.         SystemTask ( ) ;
  453.         if ( gEvent . when > 600 + l ) {
  454.  
  455.             break ;
  456.         }
  457.     }
  458.     //    Restore environs
  459.     TextMode ( srcOr ) ;
  460.     EraseRect ( & gWindow -> portRect ) ;
  461.     InvalRect ( & gWindow -> portRect ) ;
  462. }
  463.  
  464.  
  465. //    We need somewhere to send to
  466. //
  467. static void
  468. DoSelectDestination ( void )
  469. {
  470.     Str255 prompt , label , type ;
  471.  
  472.     //    Set up strings
  473.     GetIndString ( prompt , 128 , 1 ) ;
  474.     GetIndString ( label , 128 , 2 ) ;
  475.     GetIndString ( type , 128 , 3 ) ;
  476.  
  477.     //    Zero out return structs
  478.     Clear ( theLocation ) ;
  479.     Clear ( thePPCPort ) ;
  480.  
  481.     //    Get the application to talk to
  482.     hasDest = ! PPCBrowser ( prompt , label , FALSE , & theLocation , & thePPCPort ,
  483.         NULL , type ) ;
  484. }
  485.  
  486.  
  487. //    Handle the edit menu
  488. //
  489. static void
  490. EditMenu ( short item )
  491. {
  492.     //    Check for System Edit
  493.  
  494.     if ( ! SystemEdit ( item - 1 ) ) {
  495.  
  496.         switch ( item ) {
  497.  
  498.         case 3 :
  499.             TECut ( teH ) ;
  500.             break ;
  501.  
  502.         case 4 :
  503.             TECopy ( teH ) ;
  504.             break ;
  505.  
  506.         case 5 :
  507.             TEPaste ( teH ) ;
  508.             break ;
  509.  
  510.         case 6 :
  511.             TEDelete ( teH ) ;
  512.             break ;
  513.  
  514.         //    Select All
  515.         case 8 :
  516.             TESetSelect ( 0 , 32768 , teH ) ;
  517.             break ;
  518.         }
  519.     }
  520. }
  521.  
  522.  
  523. //    Update Menus - dis-/enable edit menu items
  524. //
  525. static void
  526. UpdateMenus ( void )
  527. {
  528.     short ix ;
  529.     Boolean b = 0 ;
  530.     MenuHandle mh = GetMHandle ( 130 ) ;
  531.     short start = ( * teH ) -> selStart ;
  532.     short end = ( * teH ) -> selEnd ;
  533.  
  534.     if ( ! mh ) {
  535.  
  536.         Fatal ( MemError ( ) ) ;
  537.     }
  538.     //    First, disable everything
  539.     for ( ix = 1 ; ix < 9 ; ix ++ ) {
  540.  
  541.         DisableItem ( mh , ix ) ;
  542.     }
  543.     //    For other windows, like DAs, we enable it
  544.     if ( FrontWindow ( ) != gWindow ) {
  545.  
  546.         b = 1 ;
  547.  
  548.     } else {
  549.  
  550.         //    Can always select all
  551.         EnableItem ( mh , 8 ) ;
  552.         //    If selection, can copy & clear
  553.         if ( start != end ) {
  554.  
  555.             b = 1 ;
  556.         }
  557.     }
  558.     {
  559.         long offset , len ;
  560.  
  561.         //    Check for paste
  562.         if ( 0 < ( len = GetScrap ( NULL , 'TEXT' , & offset ) ) ) {
  563.  
  564.             EnableItem ( mh , 5 ) ;
  565.         }
  566.     }
  567.     //    Maybe select some items
  568.     if ( b ) {
  569.  
  570.         for ( ix = 1 ; ix < 7 ; ix ++ ) {
  571.  
  572.             if ( ix != 2 && ix != 5 ) {
  573.  
  574.                 EnableItem ( mh , ix ) ;
  575.             }
  576.         }
  577.     }
  578. }
  579.  
  580.  
  581. //    Handle a menu selection
  582. //
  583. static void
  584. DoMenu ( unsigned long cmd )
  585. {
  586.     short menu = ( cmd >> 16 ) & 0x7fff ;
  587.     short item = cmd & 0x7fff ;
  588.     Str255 da ;
  589.     long now , then ;
  590.  
  591.     if ( ! menu || ! item ) {
  592.  
  593.         return ;
  594.     }
  595.     //    Show selection
  596.     HiliteMenu ( menu ) ;
  597.     now = TickCount ( ) ;
  598.     switch ( menu ) {
  599.  
  600.     case 128 :    //    Apple Menu
  601.         if ( item == 1 ) {
  602.  
  603.             DoAbout ( ) ;
  604.  
  605.         } else {
  606.  
  607.             GetItem ( GetMHandle ( 128 ) , item , da ) ;
  608.             OpenDeskAcc ( da ) ;
  609.         }
  610.         break ;
  611.  
  612.     case 129 :    //    File Menu
  613.         if ( item == 1 ) {
  614.  
  615.             DoSelectDestination ( ) ;
  616.  
  617.         } else {
  618.  
  619.             gRunning = 0 ;
  620.         }
  621.         break ;
  622.  
  623.     case 130 :    //    Edit Menu
  624.         EditMenu ( item ) ;
  625.         break ;
  626.     }
  627.     //    See to it we flash for at least 8 ticks
  628.     then = TickCount ( ) ;
  629.     if ( then - now < 8L ) {
  630.  
  631.         Delay ( 8L - ( then - now ) , & then ) ;
  632.     }
  633.     HiliteMenu ( 0 ) ;
  634. }
  635.  
  636.  
  637. //    Handle mouseDown in gEvent
  638. //
  639. static void
  640. Click ( void )
  641. {
  642.     WindowPtr w ;
  643.     short code ;
  644.     long pos ;
  645.     Rect limit ;
  646.  
  647.     code = FindWindow ( gEvent . where , & w ) ;
  648.  
  649.     switch ( code ) {
  650.  
  651.     case inContent :
  652.     case inGrow :
  653.         if ( FrontWindow ( ) != w ) {
  654.  
  655.             SelectWindow ( w ) ;
  656.  
  657.         } else if ( w == gWindow ) {
  658.  
  659.             ClickWindow ( ) ;
  660.         }
  661.         break ;
  662.  
  663.     case inDrag :
  664.         limit = ( * GetGrayRgn ( ) ) -> rgnBBox ;
  665.         DragWindow ( w , gEvent . where , & limit ) ;
  666.         break ;
  667.  
  668.     case inMenuBar :
  669.         UpdateMenus ( ) ;    //    Make sure menus are in OK state
  670.         pos = MenuSelect ( gEvent . where ) ;
  671.         if ( pos ) {
  672.  
  673.             DoMenu ( pos ) ;
  674.         }
  675.         break ;
  676.  
  677.     case inSysWindow :
  678.         SystemClick ( & gEvent , w ) ;
  679.         break ;
  680.     }
  681. }
  682.  
  683.  
  684. //    Handle suspend/resume event - we don't get mouseMoved since we pass
  685. //    NULL to WaitNextEvent
  686. //
  687. static void
  688. OsEvent ( void )
  689. {
  690.     if ( ( unsigned long ) gEvent . message >> 24 == 1 ) {
  691.  
  692.         isIn = gEvent . message & 1 ;
  693.         SetPort ( gWindow ) ;
  694.         if ( isIn ) {
  695.  
  696.             //    Always convert scrap when switching in
  697.             TEFromScrap ( ) ;    //    Not really necessary because we're >= 4.1...
  698.             TEActivate ( teH ) ;
  699.             if ( gNmRec . nmIcon ) {
  700.  
  701.                 //    If we're in, we don't need the flashing icon anymore...
  702.                 NMRemove ( & gNmRec ) ;
  703.                 Clear ( gNmRec ) ;
  704.             }
  705.             InitCursor ( ) ;    //    Since we use no mouse region, we have to
  706.  
  707.         } else {
  708.  
  709.             //    Convert scrap and deactivate when going out
  710.             TEToScrap ( ) ;
  711.             TEDeactivate ( teH ) ;
  712.         }
  713.     }
  714. }
  715.  
  716.  
  717. //    Handle HLE - only AppleEvents, I hope
  718. //
  719. static void
  720. HighLevelEvent ( void )
  721. {
  722.     short err = AEProcessAppleEvent ( & gEvent ) ;
  723.  
  724.     if ( err ) {
  725.  
  726.         Fatal ( err ) ;
  727.     }
  728. }
  729.  
  730.  
  731. //    Sending because we pressed enter or return
  732. //
  733. static void
  734. DoSend ( void )
  735. {
  736.     AppleEvent evt = { 0 , 0 } ;
  737.     AEAddressDesc adsc = { 0 , 0 } ;
  738.     Handle h ;
  739.     TargetID tid ;
  740.     short err ;
  741.  
  742.     //    Check whether we have anything to send to
  743.     if ( ! hasDest ) {
  744.  
  745.         DoSelectDestination ( ) ;
  746.     }
  747.     h = ( Handle ) TEGetText ( teH ) ;
  748.     if ( ! hasDest || ! h ) {
  749.  
  750.         SysBeep ( 30 ) ;
  751.         return ;
  752.     }
  753.     //    Set up the target record we need as destination
  754.     tid . sessionID = 0 ;
  755.     tid . name = thePPCPort . name ;
  756.     tid . location = theLocation ;
  757.     tid . recvrName = thePPCPort . name ;
  758.     err = AECreateDesc ( typeTargetID , ( void * ) & tid , sizeof ( tid ) , & adsc ) ;
  759.     if ( ! err ) {
  760.  
  761.         //    Make event
  762.         err = AECreateAppleEvent ( pingClass , pingMessage , & adsc , kAutoGenerateReturnID ,
  763.             kAnyTransactionID , & evt ) ;
  764.     }
  765.     if ( ! err ) {
  766.  
  767.         //    Add our text
  768.         HLock ( h ) ;
  769.         AddString ( ( unsigned char * ) * h , ( * teH ) -> teLength , userName ) ;
  770.         err = AEPutParamPtr ( & evt , pingSenderText , typeChar , * h , ( * teH ) -> teLength ) ;
  771.         HUnlock ( h ) ;
  772.         //    Clear the text
  773.         TESetText ( NULL , 0L , teH ) ;
  774.         EraseRect ( & textRect ) ;
  775.         TEUpdate ( & textRect , teH ) ;
  776.     }
  777.     if ( ! err && userName [ 0 ] ) {
  778.  
  779.         err = AEPutParamPtr ( & evt , pingSenderName , typeChar , ( void * ) & userName [ 1 ] ,
  780.             userName [ 0 ] ) ;
  781.     }
  782.     if ( ! err ) {
  783.  
  784.         //    Send the event
  785.         err = AESend ( & evt , NULL , kAENoReply | kAEAlwaysInteract | kAECanSwitchLayer ,
  786.             kAENormalPriority , kAEDefaultTimeout , NULL , NULL ) ;
  787.     }
  788.     //    Dispose descs
  789.     if ( evt . dataHandle ) {
  790.  
  791.         AEDisposeDesc ( & evt ) ;
  792.     }
  793.     if ( adsc . dataHandle ) {
  794.  
  795.         AEDisposeDesc ( & adsc ) ;
  796.     }
  797.     if ( err ) {
  798.  
  799.         Fatal ( err ) ;
  800.     }
  801. }
  802.  
  803.  
  804. //    Handle keyDown event
  805. //
  806. static void
  807. Type ( void )
  808. {
  809.     long cmd ;
  810.  
  811.     SetPort ( gWindow ) ;
  812.     if ( gEvent . modifiers & cmdKey ) {
  813.  
  814.         UpdateMenus ( ) ;    //    Make sure menus are in OK state
  815.         cmd = MenuKey ( gEvent . message & 0xff ) ;
  816.         if ( cmd ) {
  817.  
  818.             DoMenu ( cmd ) ;
  819.  
  820.         } else {
  821.  
  822.             //•    Should add word move here
  823.         }
  824.     } else {
  825.  
  826.         switch ( ( gEvent . message >> 8 ) & 0xff ) {
  827.  
  828.         case 0x24 :    //    Return
  829.         case 0x4c :    //    Enter - new KB
  830.         case 0x34 :    //    Enter - old KB and PowerBooks
  831.             DoSend ( ) ;
  832.             break ;
  833.  
  834.         default :
  835.             TEKey ( gEvent . message & 0xff , teH ) ;
  836.             break ;
  837.         }
  838.     }
  839. }
  840.  
  841.  
  842. //    Handle the event in gEvent
  843. //
  844. static void
  845. HandleEvent ( void )
  846. {
  847.     switch ( gEvent . what ) {
  848.  
  849.     case updateEvt :
  850.         Update ( ) ;
  851.         break ;
  852.  
  853.     case activateEvt :
  854.         Activate ( ) ;
  855.         break ;
  856.  
  857.     case mouseDown :
  858.         Click ( ) ;
  859.         break ;
  860.  
  861.     case keyDown :
  862.     case autoKey :
  863.         Type ( ) ;
  864.         break ;
  865.  
  866.     case osEvt :
  867.         OsEvent ( ) ;
  868.         break ;
  869.  
  870.     case kHighLevelEvent :
  871.         HighLevelEvent ( ) ;
  872.         break ;
  873.     }
  874.  
  875.     //    No operation should allow the text to become too large
  876.     if ( GetHandleSize ( ( Handle ) TEGetText ( teH ) ) >= STRING_SIZE - 1 ) {
  877.  
  878.         SysBeep ( 20 ) ;
  879.         TESetSelect ( STRING_SIZE - 2 , GetHandleSize ( ( Handle ) TEGetText ( teH ) ) , teH ) ;
  880.         TEDelete ( teH ) ;
  881.     }
  882. }
  883.  
  884.  
  885. //    Main - event loop
  886. //
  887. void
  888. main ( void )
  889. {
  890.     InitMac ( ) ;
  891.     InitApp ( ) ;
  892.     InitCursor ( ) ;    //    Don't want a watch...
  893.  
  894.     while ( gRunning ) {
  895.  
  896.         //    In the background, we sleep for a long time. In the foreground,
  897.         //    we need to flash a caret, thus we use GetCaretTime.
  898.         if ( WaitNextEvent ( -1 , & gEvent , isIn ? GetCaretTime ( ) : 0x7fff , NULL ) ) {
  899.  
  900.             HandleEvent ( ) ;
  901.         }
  902.         if ( isIn && FrontWindow ( ) == gWindow ) {
  903.  
  904.             //    Only flash caret while in the foreground
  905.             TEIdle ( teH ) ;
  906.         }
  907.     }
  908. }
  909.  
  910.